package com.xbongbong.paas.connection.help;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.connection.enums.BusinessCodePrefixEnum;
import com.xbongbong.paas.connection.enums.StandardInvoiceTypeEnum;
import com.xbongbong.paas.connection.enums.StandardPhoneTypeEnum;
import com.xbongbong.paas.connection.pojo.connector.AddressCommonPojo;
import com.xbongbong.paas.connection.pojo.connector.ContactCommonPojo;
import com.xbongbong.paas.connection.pojo.connector.InvoiceCommonPojo;
import com.xbongbong.paas.connection.pojo.connector.PhoneCommonPojo;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.ItemPoJo;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.redis.RedisPrefixConstant;
import com.xbongbong.paas.redis.RedisTimeConstant;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.GaodeGeoHelper;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.enums.ErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ProErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.domain.entity.CustomerInvoiceEntity;
import com.xbongbong.saas.domain.entity.ProductCategoryEntity;
import com.xbongbong.saas.domain.entity.ext.ContactEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.model.ContactModel;
import com.xbongbong.saas.model.CustomerInvoiceModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.ProductCategoryModel;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;

@Component
public class ConnectorFormatHelper {
	private static final Logger LOG = LoggerFactory.getLogger(ConnectorFormatHelper.class);
	@Resource
	private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
	@Resource
	private PaasFormExplainModel paasFormExplainModel;
	@Resource
	private ContactModel contactModel;
	@Resource
	private CustomerModel customerModel;
	@Resource
	private ProductCategoryModel productCategoryModel;
	@Resource
	private CustomerInvoiceModel customerInvoiceModel;
	@Resource
	private PaasRedisHelper paasRedisHelper;
	/**
	 *
	 * @param phoneArray
	 * @param fieldAttr
	 * @return
	 */
	public List<PhoneCommonPojo> phoneFormat(JSONArray phoneArray, FieldAttrEntity fieldAttr) throws XbbException {
		List<? extends FieldAttrEntity> subExplainList = fieldAttr.getSubForm().getItems();
		Map<String, FieldAttrEntity> subExplainMap = ExplainUtil.getExplainMapByList(subExplainList);
		List<PhoneCommonPojo> phoneList = new ArrayList<>();
		if (Objects.nonNull(phoneArray)) {
			for (Object phoneObject : phoneArray) {
				JSONObject phoneJson = (JSONObject)phoneObject;
				if (Objects.isNull(phoneJson) || phoneJson.isEmpty()) {
				    continue;
                }
				PhoneCommonPojo phoneCommonPojo = new PhoneCommonPojo();
				String typeCode = phoneJson.getString("text_1");
				String value = phoneJson.getString("text_2");

				FieldAttrEntity subFieldAttr = subExplainMap.get("text_1");
				List<ItemPoJo> items = subFieldAttr.getItems();
				//默认为mobile
				String type = "mobile";
				try {
					type = getComboText(items, typeCode);
				} catch (XbbException e) {
				    LOG.error("getComboText error,fieldAttr:" + JSONObject.toJSONString(fieldAttr) + ",attr:" + fieldAttr.getAttr() + ",phoneJson:" + phoneJson.toJSONString(), e);
				}
				phoneCommonPojo.setType(type);
				phoneCommonPojo.setValue(value);
				phoneList.add(phoneCommonPojo);
				addStandardPhoneType(phoneList, value);
			}
		}
		return phoneList;
	}

	private void addStandardPhoneType(List<PhoneCommonPojo> phoneList, String value) {
		PhoneCommonPojo phoneCommonPojo = new PhoneCommonPojo();
		phoneCommonPojo.setValue(value);
		if (StringUtil.isMobile(value)) {
			phoneCommonPojo.setType(StandardPhoneTypeEnum.MOBILE.getAlias());
			phoneList.add(phoneCommonPojo);
			return;
		}
		if (StringUtil.isPhone(value)) {
			phoneCommonPojo.setType(StandardPhoneTypeEnum.PHONE.getAlias());
			phoneList.add(phoneCommonPojo);
			return;
		}
		if (StringUtil.isEmail(value)) {
			phoneCommonPojo.setType(StandardPhoneTypeEnum.EMAIL.getAlias());
			phoneList.add(phoneCommonPojo);
			return;
		}
	}


	/**
	 * 获取text
	 * @param items
	 * @param comboValue
	 * @return
	 */
	public String getComboText(List<ItemPoJo> items, String comboValue) throws XbbException {
		for (ItemPoJo item : items) {
			String value = item.getValue().toString();
			if (Objects.equals(comboValue, value)) {
				return item.getText();
			}
		}
		if (hasOtherOption(items)) {
			return comboValue;
		} else {
			throw new XbbException(ProErrorCodeEnum.API_ERROR_701041);
		}
	}

	/**
	 * 判断是否有其他选项
	 * @param items
	 * @return
	 */
	private boolean hasOtherOption(List<ItemPoJo> items) {
		for (ItemPoJo item : items) {
			if (Objects.equals(item.getIsOther(), 1)) {
				return true;
			}
		}
		return false;
	}

	/**
	 *
	 * @param data
	 * @param addressAttr
	 * @param addressMap key：province_省名/city_市名/district_区名，value：adcode
	 * @return
	 */
	public AddressCommonPojo addressFormat(JSONObject data, String addressAttr, Map<String, String> addressMap) {
		JSONObject addressObj = data.getJSONObject(addressAttr);
		AddressCommonPojo addressCommonPojo = new AddressCommonPojo();
		if (Objects.nonNull(addressObj)) {
			String province = addressObj.getString(PaasConstant.PROVINCE);
			String city = addressObj.getString(PaasConstant.CITY);
			String district = addressObj.getString(PaasConstant.DISTRICT);
			addressCommonPojo.setProvince(province);
			addressCommonPojo.setCity(city);
			addressCommonPojo.setDistrict(district);
			addressCommonPojo.setDetailAddress(addressObj.getString(PaasConstant.ADDRESS));
			String adcode = getAdcode(province, city, district, addressMap);
			addressCommonPojo.setCode(adcode);
		}
		return addressCommonPojo;
	}

	/**
	 * 获取省市区对应的
	 * @param province 省
	 * @param city 市
	 * @param district 区
	 * @param addressMap key：province_省名/city_市名/district_区名，value：adcode
	 * @return
	 * 创建时间 2021/8/17 9:33 AM
	 * 修改时间 2021/8/17 9:33 AM
	 * @author chy
	 */
	private String getAdcode(String province, String city, String district, Map<String, String> addressMap) {
		String adcode = "";
		String districtKey = "district_" + district;
		if (addressMap.containsKey(districtKey)) {
			return addressMap.get(districtKey);
		}
		String cityKey = "city_" + city;
		if (addressMap.containsKey(cityKey)) {
			return addressMap.get(cityKey);
		}
		String provinceKey = "province_" + province;
		if (addressMap.containsKey(provinceKey)) {
			return addressMap.get(provinceKey);
		}
		return adcode;
	}

	/**
	 * 获取map，key：province_省名/city_市名/district_区名，value：adcode
	 * @return
	 * 创建时间 2021/8/17 9:31 AM
	 * 修改时间 2021/8/17 9:31 AM
	 * @author chy
	 */
	public Map<String, String> getAddressMap() {
		Map<String, String> addressMap = new HashMap<>();
		if (paasRedisHelper.hasKey(RedisPrefixConstant.SUB_DEP_ID_MAP, null)) {
			//存在缓存
			Map<Object, Object> map = paasRedisHelper.getAllHashValue(RedisPrefixConstant.SUB_DEP_ID_MAP, null);
			map.forEach((key, value) -> {
				try {
					addressMap.put(key.toString(), value.toString());
				} catch (NumberFormatException | ClassCastException e1) {
					//do nothing
				}
			});
			return addressMap;
		}
		JSONObject addressJson = GaodeGeoHelper.district();
		Map<Object, Object> retMap = new HashMap<>();
		JSONArray countryArray = addressJson.getJSONArray("districts");
		if (Objects.isNull(countryArray) || countryArray.isEmpty()) {
			//国家信息为空
		}
		JSONObject countryJson = countryArray.getJSONObject(0);
		JSONArray provinceArray = countryJson.getJSONArray("districts");
		String provinceName = "";
		String cityName = "";
		String districtName = "";
		String adcode = "";
		for (Object provinceObject : provinceArray) {
			JSONObject provinceJson = (JSONObject)provinceObject;
			provinceName = provinceJson.getString("name");
			adcode = provinceJson.getString("adcode");
			String provinceKey = "province_" + provinceName;
			addressMap.put(provinceKey, adcode);
			retMap.put(provinceKey, adcode);
			JSONArray cityArray = provinceJson.getJSONArray("districts");
			for (Object cityObject : cityArray) {
				JSONObject cityJson = (JSONObject)cityObject;
				cityName = cityJson.getString("name");
				adcode = cityJson.getString("adcode");
				String cityKey = "city_" + cityName;
				addressMap.put(cityKey, adcode);
				retMap.put(cityKey, adcode);
				JSONArray districtArray = cityJson.getJSONArray("districts");
				for (Object districtObject : districtArray) {
					JSONObject districtJson = (JSONObject)districtObject;
					districtName = districtJson.getString("name");
					adcode = districtJson.getString("adcode");
					String districtKey = "district_" + districtName;
					addressMap.put(districtKey, adcode);
					retMap.put(districtKey, adcode);
				}
			}
		}
		paasRedisHelper.setAllHashValue(RedisPrefixConstant.SUB_DEP_ID_MAP, null, retMap, RedisTimeConstant.HOUR_DURATION);
		return addressMap;
	}

	public List<ContactCommonPojo> getContactList(String corpid, Long customerId) throws XbbException {
		SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
		BoolQueryBuilder boolQueryBuilder = boolQuery();
		boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
		boolQueryBuilder.filter(termQuery("del", 0));
		boolQueryBuilder.filter(termQuery("data." + ContactEnum.CUSTOMER_NAME.getAttr(), customerId));
		boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTACT.getType()));
		sourceBuilder.query(boolQueryBuilder);
		List<String> fieldList = Arrays.asList(BasicConstant.DATAID, BasicConstant.SERIAL_NO, ContactEnum.NAME.getAttr(), ContactEnum.PHONE.getAttr(),
				ContactEnum.EMAIL.getAttr(), ContactEnum.ADDRESS.getAttr());
		EsUtil.setFieldList(sourceBuilder, fieldList);
		PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 0, PaasConstant.ES_MAX_PAGE_SIZE);
		SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTACT.getIndex());
		searchRequest.source(sourceBuilder);
		XbbAggregatedPage<ContactEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, ContactEntityExt.class);
		if (esEntities == null) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
		}
		List<ContactCommonPojo> contacts = new ArrayList<>();
		List<ContactEntityExt> resultList =  esEntities.getContent();
		Long formId = 0L;
		FieldAttrEntity fieldAttrEntity = null;
		if (!resultList.isEmpty()) {
			formId = resultList.get(0).getFormId();
			fieldAttrEntity = getFieldAttr(corpid, formId, ContactEnum.PHONE.getAttr());
		}
		Map<String, String> addressMap = getAddressMap();
		for (ContactEntityExt contactEntity : resultList) {
			JSONObject contactData = contactEntity.getData();
			String contactName = contactData.getString(ContactEnum.NAME.getAttr());
			JSONArray phoneArray = contactData.getJSONArray(ContactEnum.PHONE.getAttr());
			String contactEmail = contactData.getString(ContactEnum.EMAIL.getAttr());
			ContactCommonPojo contactCommonPojo = new ContactCommonPojo();
			String serialNo = contactEntity.getSerialNo();
			if (StringUtil.isEmpty(serialNo)) {
                serialNo = BusinessCodePrefixEnum.CONTACT_CODE_PREFIX.getPrefix() + contactEntity.getId().toString();
                contactEntity.setId(contactEntity.getDataId());
                contactEntity.setSerialNo(serialNo);
                //data中数据不全，不更新data
				contactEntity.setData(null);
                LOG.info("update contact serialNo");
                contactModel.update(contactEntity);
            }
			contactCommonPojo.setCode(serialNo);
			contactCommonPojo.setName(contactName);
//			contactCommonPojo.setEmail(contactEmail);
			contactCommonPojo.setAddress(addressFormat(contactData, ContactEnum.ADDRESS.getAttr(), addressMap));
			List<PhoneCommonPojo> phoneList = phoneFormat(phoneArray, fieldAttrEntity);
			addEmailToPhones(phoneList, contactEmail);
			contactCommonPojo.setContactTypeList(phoneList);
			contacts.add(contactCommonPojo);
		}
		return contacts;
	}

	/**
	 * 邮箱追加到联系方式中（钉钉规范）
	 * @param phoneList
	 * @param contactEmail
	 */
	private void addEmailToPhones(List<PhoneCommonPojo> phoneList, String contactEmail) {
		if (StringUtil.isEmpty(contactEmail)) {
			return;
		}
		PhoneCommonPojo phoneCommonPojo = new PhoneCommonPojo();
		phoneCommonPojo.setType(StandardPhoneTypeEnum.EMAIL.getAlias());
		phoneCommonPojo.setValue(contactEmail);
		phoneList.add(phoneCommonPojo);
	}

	/**
	 * 获取单个字段解释（非工单）
	 * @param corpid
	 * @param formId
	 * @param attr
	 * @return
	 * @throws XbbException
	 */
	public FieldAttrEntity getFieldAttr(String corpid, Long formId, String attr) throws XbbException {
		Map<String, FieldAttrEntity> explainMap = getExplainMap(corpid, formId);
		return explainMap.get(attr);
	}

	/**
	 * 获取字段解释（非工单）
	 * @param corpid
	 * @param formId
	 * @return
	 * @throws XbbException
	 */
	private Map<String, FieldAttrEntity> getExplainMap(String corpid, Long formId) throws XbbException{
		PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formId, corpid);
		if ( Objects.isNull(paasFormExplainEntity) ) {
			throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
		}
		return ExplainUtil.getExplainMap(paasFormExplainEntity.getExplains(), null);
	}

	/**
	 * 钉钉连接器写操作 30次/秒
	 * @param corpid
	 */
	public void connectorWait(String corpid) {
		String prefix = "ddConnector";
		Long writeNum = paasRedisHelper.getIncrNumByOne(prefix, corpid, 500, TimeUnit.MILLISECONDS);
		while (writeNum > 13) {
			//睡500ms
			LOG.info("sleep 500ms");
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			writeNum = paasRedisHelper.getIncrNumByOne(prefix, corpid, 500, TimeUnit.MILLISECONDS);
		}
		LOG.info("writeNum:" + writeNum);
	}

    /**
     * 通过客户id获取客户编号
     * @param corpid
     * @param customerId
     * @return
     */
    public String getCustomerCode(String corpid, Long customerId) {
        CustomerEntityExt customer = customerModel.getByKey(customerId, corpid);
        return getCustomerCode(customer);
    }

    /**
     * 通过客户对象获取客户编号
     * @param customer
     * @return
     */
    public String getCustomerCode(CustomerEntityExt customer) {
        if (Objects.isNull(customer)) {
            return null;
        }
        String serialNo = customer.getSerialNo();
        if (StringUtil.isEmpty(serialNo)) {
            serialNo = BusinessCodePrefixEnum.CUSTOMER_CODE_PREFIX.getPrefix() + customer.getId();
        }
        return serialNo;
    }

	/**
	 * 通过联系人id获取联系人编号
	 * @param corpid
	 * @param contactId
	 * @return
	 */
	public String getContactCode(String corpid, Long contactId) {
		ContactEntityExt contact = contactModel.getByKey(contactId, corpid);
		return getCustomerCode(contact);
	}

	/**
	 * 通过联系人对象获取联系人编号
	 * @param contact
	 * @return
	 */
	public String getCustomerCode(ContactEntityExt contact) {
		if (Objects.isNull(contact)) {
			return null;
		}
		String serialNo = contact.getSerialNo();
		if (StringUtil.isEmpty(serialNo)) {
			serialNo = BusinessCodePrefixEnum.CONTACT_CODE_PREFIX.getPrefix() + contact.getId();
		}
		return serialNo;
	}

    /**
     * 通过产品分类id获取产品分类编号
     * @param corpid
     * @param categoryId
     * @return
     */
    public String getCategoryCode(String corpid, Long categoryId) {
        ProductCategoryEntity productCategory = productCategoryModel.getByKey(categoryId, corpid);
        if (Objects.isNull(productCategory)) {
            return null;
        }
        String serialNo = productCategory.getSerialNo();
        if (StringUtil.isEmpty(serialNo)) {
            serialNo = BusinessCodePrefixEnum.PRODUCT_CATEGORY_CODE_PREFIX.getPrefix() + categoryId;
        }
        return serialNo;
    }

	public List<InvoiceCommonPojo> invoiceInfoFormat(String corpid, Long id) {
		Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
		param.put(ParameterConstant.CORPID, corpid);
		param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
		param.put("customerId", id);
		List<CustomerInvoiceEntity> customerInvoiceEntityList = customerInvoiceModel.findEntitys(param);
		if (Objects.isNull(customerInvoiceEntityList) || customerInvoiceEntityList.isEmpty()) {
			return null;
		}
		List<InvoiceCommonPojo> invoiceInfos = new ArrayList<>();
		for (CustomerInvoiceEntity customerInvoiceEntity : customerInvoiceEntityList) {
			InvoiceCommonPojo invoiceCommonPojo = new InvoiceCommonPojo();
			Integer code = null;
			try {
				code = Integer.parseInt(customerInvoiceEntity.getTitleType());
			} catch (Exception e) {
			    //没有存值，不做处理
			}
			StandardInvoiceTypeEnum standardInvoiceTypeEnum = StandardInvoiceTypeEnum.getByCode(code);
			if (Objects.nonNull(standardInvoiceTypeEnum)) {
				invoiceCommonPojo.setInvoiceTitleType(standardInvoiceTypeEnum.getAlias());
			}
			invoiceCommonPojo.setInvoiceTitleName(customerInvoiceEntity.getTitle());
			invoiceCommonPojo.setInvoiceTitleCode(customerInvoiceEntity.getTaxpayerNo());
			invoiceCommonPojo.setTelephone(customerInvoiceEntity.getRegisteredPhone());
			invoiceCommonPojo.setAddress(customerInvoiceEntity.getInvoiceAddress());
			invoiceCommonPojo.setBankName(customerInvoiceEntity.getBank());
			invoiceCommonPojo.setBankAccount(customerInvoiceEntity.getAccount());
			invoiceInfos.add(invoiceCommonPojo);
		}
		return invoiceInfos;
	}
}